﻿// ==UserScript==
// @name         user-web
// @namespace    https://user-web.googlecode.com/
// @version      9
// @description  insert user styles
// @grant        GM_addStyle
// @grant        GM_setClipboard
// @include      http*://*/*
// @include      file:///C:/Users/*/Documents/Scripts/test.htm
// @include      file:///C:/Users/*/Downloads/*.htm
// @exclude      https://localhost:44300/TestLocal.htm
// @exclude      http://localhost:3*
// @exclude      https://docs.google.com*
// @copyright    2010+, james_zerty
// @require      https://user-web.googlecode.com/svn/trunk/Scripts/jquery/jquery-2.1.0.js
// @require      https://user-web.googlecode.com/svn/trunk/Scripts/jquery/jquery.cookie.js
// ==/UserScript==

"use strict";

/* TODO:
*  on auto find make sure the original element is in the found parent
*  widen content column
*  only increase font size on code blocks
*  find column by checking parent nodes for large width changes
*  reinstate read advanced find
*  ff native menu - can't work out how force show on selection. need to implement show/hide
*  +skip when me.longClickEvent is null - happens in outlook
*  +go to url
*  +hide menu after 10s
*  +fix open on left off screen
*  +fix squish when open off rhs
*  +toggle dblclick click style reload
*  +read clearer
*  +remove column
*  +remove cell - go up tree until element is taller then delete
*  +better separator
*  +better read links toggle
*/

try {
    var isTop = window.top == window.self;

    if (isTop) {
        var userWeb = new function () {
            var me = this;

            me.load = function () {
                me.url = document.location.href;
                me.doAuto = me.cookie().auto;
                me.isLinux = navigator.userAgent.indexOf("Linux") > -1;
                me.fontSize = me.isLinux ? 15 : 16;
                me.useOwnMenu = true;
                me.menuTimeoutTime = 1000;

                me.log("page url", me.url);
                //me.log("navigator.userAgent", navigator.userAgent);

                me.debug = { localUrls: 0, uniqueUrls: 0, reloader: 0, autoShow: 0 };

                if (me.url.match(/localhost.*test.*\.htm/i) != null) {
                    me.debug = { localUrls: 0, uniqueUrls: 0, reloader: 1, autoShow: 0 };
                }

                if (navigator.userAgent.indexOf("Windows NT 6.3; WOW64") > -1
                 || navigator.userAgent.indexOf("Windows NT 6.1; WOW64") > -1) {
                    me.debug.localUrls = 1;
                }

                if (me.debug.reloader) {
                    /*$(document).dblclick(function () {
                    document.location.href = document.location.href;
                    });*/
                    document.oncontextmenu = function (e) {
                        document.location.reload(true);
                        return false;
                    };
                }

                me.loadUserStyle();
                me.tryAutoReadr();
                me.bindLongClick();

                me.initMenu = function (aEvent) {
                    try {
                        me.showMenu(aEvent);

                        var node = aEvent.target; // aEvent.target is the element you right click on

                        //if (node.localName == "img") {
                        var item = document.querySelectorAll("#UserWebMenu menuitem");
                        body.setAttribute("contextmenu", "UserWebMenu");

                        me.log("items", item.length);

                        //for (var i = item.length - 1; i > -1; i--) {
                        //    item[i].setAttribute("targetNode", node.tagName);

                        //    if (i > 5) {
                        //        me.log("hiding");
                        //        //item[i].hidden = true;
                        //    }
                        //}

                        //$("#UserWebMenuReadr")[0].disabled = true;
                        //me.ulSearch[0].hidden = true;
                        //me.linkDeleteColumn[0].style.display = "none"; //.disabled = true;
                        //}
                        //else {
                        //    body.removeAttribute("contextmenu");
                        //    item.removeAttribute("imageURL");
                        //}
                    }
                    catch (ex) {
                        me.error(ex);
                    }
                };

                if (!me.useOwnMenu) {
                    var body = document.body;
                    body.addEventListener("contextmenu", me.initMenu, false);
                }

                if (me.debug.autoShow) {
                    me.run(function () {
                        var e = {
                            pageX: 400,
                            pageY: 300
                        };

                        me.selectedText = "test";
                        me.bindMenuClick();
                        me.showMenu(e);

                        //window.setTimeout(function () {
                        //    me.log("autoShow", $('img').length);
                        //    $('#txt1')
                        //        .triggerHandler('contextmenu');
                        //}, 1000);
                    });
                }
            };

            me.getRoot = function () {
                return me.debug.localUrls ? "https://localhost:44300/" : "https://user-web.googlecode.com/svn/trunk/";
            }

            me.log = function () {
                log.apply(this, arguments);
            };

            me.cookie = function (key, value) {
                var cookie;

                if ($.cookie) {
                    $.cookie.json = true;

                    cookie = $.cookie("user-web");
                }

                if (cookie == null || cookie == "") {
                    cookie = {
                        auto: false
                    };
                }

                if (key != null) {
                    cookie[key] = value;

                    if ($.cookie) {
                        $.cookie("user-web", cookie, { expires: 9999 });
                    }
                }

                return cookie;
            };

            me.run = function (fn) {
                try {
                    fn();
                }
                catch (ex) {
                    me.error(ex);
                }
            };

            me.error = function (ex) {
                var msg = ex.message;

                if (!msg) {
                    for (var i in ex) {
                        msg += ex[i] + " ";
                    }
                }

                me.log("run error", msg);
            };

            me.saveSelection = function (e) {
                var text = "";

                if ($(e.target).is("input[type='text']") || $(e.target).is("textarea")) {
                    text = me.getTextFieldSelection(e.target);
                }
                else {
                    text = window.getSelection().toString();
                }

                if (text) {
                    me.selectedText = text;
                    //me.log("me.selectedText", me.selectedText);

                    return true;
                }
                else {
                    return false;
                }
            };

            me.getTextFieldSelection = function (textField) {
                return textField.value.substring(textField.selectionStart, textField.selectionEnd);
            }

            /* events ********************************************************************************************************************** */

            me.bindLongClick = function () {
                //me.longClickEvent = null;

                $('html').mouseup(function (e) {
                    me.run(function () {
                        if (e.button != 0) {
                            return;
                        }

                        if (me.saveSelection(e)) {
                            if (me.menuShowing) {
                                me.hideMenu();
                                return;
                            }

                            var tagName = e.target == null ? "UNKNOWN" : e.target.tagName;

                            switch (tagName) {
                                //case "A":   
                                case "IMG":  //img doesn't clear selection
                                case "HTML": //scrollbar
                                    me.log("not showing!", e.target.tagName, e.target, e.pageX, e.pageY);
                                    me.hideMenu();
                                    //me.longClickEvent == null;
                                    return;
                            }

                            me.log("showing", e.target.tagName, e.target, e.pageX, e.pageY);


                            var text = me.selectedText;
                            if (text.length > 20) {
                                text = text.substr(0, 20) + "...";
                            }

                            //me.setLongClickEvent(e);
                            me.showMenu(e);
                            me.bindMenuClick();
                            e.preventDefault();
                            e.stopPropagation();
                            return;
                        }

                        if (me.longClickEvent != null) {
                            var diffT = new Date() - me.longClickEvent.time;
                            var diffX = Math.abs(e.clientX - me.longClickEvent.event.clientX);
                            var diffY = Math.abs(e.clientY - me.longClickEvent.event.clientY);

                            if (diffT > 1000 & diffT < 3000 & diffX < 2 && diffY < 2) {
                                me.log("cancelling click 1");
                                me.selectedText = null;
                                me.setLongClickEvent(e);
                                me.showMenu(e);
                                me.bindMenuClick();
                                e.preventDefault();
                                e.stopPropagation();
                                return false;
                            }
                            else {
                                me.longClickEvent = null;
                            }
                        }
                    });
                }).mousedown(function (e) {
                    me.run(function () {
                        //me.setLongClickEvent(e);
                    });
                });
            };

            me.setLongClickEvent = function (e) {
                me.log("setLongClickEvent");
                me.longClickEvent = {
                    time: new Date(),
                    event: e
                };
            };

            me.bindMenuClick = function () {
                if (!me.isClickBound) {
                    me.isClickBound = true;

                    //$('body').bind("click", function (e) {
                    me.menu.bind("click", function (e) {
                        me.run(function () {
                            me.onMenuClick(e);
                        });
                    });
                }
            };

            me.onMenuClick = function (e) {
                if (me.longClickEvent) {
                    var diff = new Date() - me.longClickEvent.time;

                    if (diff > 150) {
                        me.hideMenu();
                    }
                    else {
                        me.log("cancelling click 2");
                        e.preventDefault();
                        e.stopPropagation();
                        return false;
                    }
                }
                else {
                    me.hideMenu();
                }
            };

            me.onKeyDown = function (e) {
                me.run(function () {

                    switch (e.keyCode) {
                        case 16: // shift
                        case 17: // ctrl
                        case 18: // alt
                            return;
                        case 107: // num plus
                            if (e.ctrlKey && e.shiftKey) {
                                me.setFont(1);
                            }

                            break;
                        case 109: // num minus
                            if (e.ctrlKey && e.shiftKey) {
                                me.setFont(-1);
                            }

                            break;
                        case 32: // space
                            if (me.menuShowing) {
                                me.runReadr(me.clickEvent);
                                e.preventDefault();
                                e.stopPropagation();
                            }

                            break;
                    }

                    me.hideMenu();
                });
            };

            /* display ********************************************************************************************************************** */

            me.showMenu = function (e) {
                me.menuShowing = true;
                me.clickEvent = e;

                if (!me.useOwnMenu) {
                    //me.log("show1", e.target);
                    //$("body").contextmenu("open");

                    /*
                    http://wwwendt.de/tech/demo/jquery-contextmenu/jquery.ui-contextmenu.js
                    /** Open context menu on a specific target (must match options.delegate)
                    *  Optional `extraData` is passed to event handlers as `ui.extraData`.
	                

                    this._show(this.$menu, this.options.show, function() {
                    self._trigger.call(self, "open", event, ui);
                    });

                    open: function(target, extraData) {
                    // Fake a 'contextmenu' event
                    extraData = extraData || {};
                    var e = jQuery.Event("contextmenu", { target: target.get(0), extraData: extraData });
                    return this.element.trigger(e);
                    }

                    var extraData = extraData || {};
                    var e2 = $.Event("contextmenu", {  });
                    $("body").trigger(e2);
                    //$(e.target).trigger(e2);
                    */

                    //me.log("show2");

                    //return;
                }

                var adjustY = -10;
                var adjustX = 160;
                var offsetY = 0;
                var offsetX = 0;

                if (me.menu == null) {
                    me.createMenu();
                }
                else {
                    me.menu.show();
                }

                if (me.selectedText) {
                    offsetY = 10;
                    offsetX = 70;
                    me.ulReadr.show();
                    me.ulSearch.show();
                    me.ulReadr.css("min-height", "161px"); //hack for the vertical separator
                }
                else {
                    me.ulReadr.show();
                    me.ulSearch.hide();
                    me.ulReadr.css("min-height", "1px");
                }

                var left = e.pageX - adjustX + offsetX;

                if (left < 10) {
                    left = 10;
                }

                me.menu.css({
                    top: e.pageY - adjustY + offsetY + 'px',
                    left: left + 'px'
                });

                var pos = me.menu.position();
                pos.height = me.menu.height();
                pos.width = me.menu.width();
                pos.bottom = pos.top + pos.height;
                pos.right = pos.left + pos.width;

                var wpos = [];
                wpos.height = $(window).height();
                wpos.width = $(window).width();
                wpos.scrollTop = $(window).scrollTop();
                wpos.scrollBottom = wpos.scrollTop + wpos.height;

                if (pos.bottom > wpos.scrollBottom) {
                    me.menu.css("top", e.pageY - pos.height - 20 + 'px');
                }

                if (pos.top < 0) {
                    me.menu.css("top", '0px');
                }

                if (pos.right > wpos.width) {
                    me.menu.css("left", wpos.width - pos.width - 20 + "px");
                }

                if (pos.left < 0) {
                    me.menu.css("left", "0px");
                }

                me.menuTimeoutClear();
                me.menuTimeoutSet();
            };

            me.menuTimeoutClear = function () {
                if (typeof me.menuTimeoutId == "number") {
                    window.clearTimeout(me.menuTimeoutId);
                    delete me.menuTimeoutId;
                }
            };

            me.menuTimeoutSet = function () {
                me.menuTimeoutId = window.setTimeout(function () {
                    me.hideMenu();
                }, me.menuTimeoutTime);
            };

            me.hideMenu = function () {
                if (me.menu && me.menuShowing) {
                    me.menu.hide();
                    me.menuTimeoutClear();
                }

                me.menuShowing = false;
            };

            me.createMenu = function () {
                if (me.menu) {
                    return;
                }

                $('body').bind("keydown", function (e) {
                    me.run(function () {
                        me.onKeyDown(e);
                    });
                });

                me.addStyles();

                if (me.useOwnMenu) {
                    me.menu = $("<div id='UserWebMenu' class='user-web-menu'>");
                    me.ulReadr = $("<ul class='user-web-readr'>");

                    me.menu.hover(
                        function () { // on hover
                            me.menuTimeoutClear();
                        },
                        function () { // on exit
                            me.menuTimeoutClear();
                            me.menuTimeoutSet();
                        }
                    );
                }
                else {
                    me.menu = $("<menu id='UserWebMenu' type='context'>");
                    me.ulReadr = $("<menu id='UserWebMenuReadr' label='Readr'>");
                }

                me.menu.append(me.ulReadr);

                me.linkDeleteColumn =
                    me.addLink(me.ulReadr, "Delete column", function () {
                        me.run(function () {
                            me.runReadr(me.clickEvent, "remove-column");
                        });
                    });

                me.linkDeleteCell =
                    me.addLink(me.ulReadr, "Delete cell", function () {
                        me.run(function () {
                            me.runReadr(me.clickEvent, "remove-cell");
                        });
                    });

                me.addSeparator(me.ulReadr);

                me.linkRunReadr =
                    me.addLink(me.ulReadr, "Read", function () {
                        me.run(function () {
                            me.runReadr(me.clickEvent);
                        });
                    });

                me.linkRunReadrPopout =
                    me.addLink(me.ulReadr, "Popout", function () {
                        me.run(function () {
                            me.runReadr(me.clickEvent, "popout");
                        });
                    });

                me.separatorRead = me.addSeparator(me.ulReadr).hide();

                me.linkLinkFontUp =
                    me.addLink(me.ulReadr, "Font bigger", function () {
                        me.run(function () {
                            me.setFont(1);
                        });
                    }).hide();

                me.linkLinkFontDown =
                    me.addLink(me.ulReadr, "Font smaller", function () {
                        me.run(function () {
                            me.setFont(-1);
                        });
                    }).hide();

                me.linkRunReadrPlus =
                    me.addLink(me.ulReadr, "Read Clearer", function () {
                        me.run(function () {
                            me.addStyle(//TODO: move to own function
                                '.readr-container * {' +
                                    'color: #000 !important;' +
                                '}');
                        });
                    }).hide();

                me.addSeparator(me.ulReadr);

                me.linkUndoReadr =
                    me.addLink(me.ulReadr, "Undo Read", function () {
                        me.run(function () {
                            me.undoReadr();
                        });
                    }).hide();

                me.linkDisableAutoReadr =
                    me.addLink(me.ulReadr, "Disable Auto Read", function () {
                        me.run(function () {
                            me.disableAutoReadr();
                        });
                    }).hide();

                me.linkEnableAutoReadr =
                    me.addLink(me.ulReadr, "Enable Auto Read", function () {
                        me.run(function () {
                            me.enableAutoReadr();
                        });
                    }).hide();

                me.userStyleSeparator = me.addSeparator(me.ulReadr);

                me.linkReloadStyle =
                    me.addLink(me.ulReadr, "Reload style", function () {
                        me.run(function () {
                            me.debug.uniqueUrls = 1;
                            me.loadUserStyle();
                        });
                    }).hide();

                me.linkReloadStyleOnDblClick =
                    me.addLink(me.ulReadr, "Reload style on double click", function () {
                        $('body').bind("dblclick.uws", function () {
                            me.run(function () {
                                me.debug.uniqueUrls = 1;
                                me.loadUserStyle();
                            });

                            if (window.getSelection) {
                                window.getSelection().removeAllRanges();
                            }
                            else if (document.selection) {
                                document.selection.empty();
                            }

                            me.hideMenu();
                        });

                        me.reloadStyleOnDblClickIsBound = true;
                        me.linkReloadStyleOnDblClick.hide();
                        me.linkReloadStyleOnDblClickOff.show();
                    }).hide();

                me.linkReloadStyleOnDblClickOff =
                    me.addLink(me.ulReadr, "Reload style on double click - cancel", function () {
                        $('body').unbind("dblclick.uws");
                        me.linkReloadStyleOnDblClick.show();
                        me.linkReloadStyleOnDblClickOff.hide();
                    }).hide();

                me.linkUnloadStyle =
                    me.addLink(me.ulReadr, "Unload style", function () {
                        me.run(function () {
                            me.unloadUserStyle();
                        });
                    }).hide();

                me.addSeparator(me.ulReadr);

                me.addLink(me.ulReadr, "Refresh", null, document.location.href);

                if (me.useOwnMenu) {
                    me.ulSearch = $("<ul class='user-web-search'>");
                }
                else {
                    me.ulSearch = $("<menu id='UserWebMenuSearch' label='Search'>");
                }

                me.menu.append(me.ulSearch);

                me.addLink(me.ulSearch, "Copy", function () { me.setClipboard(); });
                me.linkNavigateTo = me.addLink(me.ulSearch, "Go to", function () { me.navigateTo(me.selectedText); });
                me.addSeparator(me.ulSearch);
                me.linkSearchTitle = me.addListItem(me.ulSearch, "Search..."); //.addClass("bold");
                me.addLink(me.ulSearch, "Google", function () { me.openSearch("https://www.google.co.uk/search?q=TESTSEARCH"); });
                me.addLink(me.ulSearch, "Google Define", function () { me.openSearch("https://www.google.co.uk/search?q=define:TESTSEARCH"); });
                me.addLink(me.ulSearch, "Google Maps", function () { me.openSearch("https://maps.google.co.uk/maps?q=TESTSEARCH"); });
                me.addLink(me.ulSearch, "Stack Overflow", function () { me.openSearch("https://www.google.co.uk/search?q=site%3Astackoverflow.com+TESTSEARCH"); });
                me.addLink(me.ulSearch, "Super User", function () { me.openSearch("https://www.google.co.uk/search?q=site%3Asuperuser.com+TESTSEARCH"); });
                me.addLink(me.ulSearch, "Twitter", function () { me.openSearch("https://twitter.com/search?q=TESTSEARCH&src=typd"); });
                me.addLink(me.ulSearch, "Wikipedia", function () { me.openSearch("http://en.wikipedia.org/wiki/Special:Search?search=TESTSEARCH&go=Go"); });
                //me.addLink(me.ulSearch, "IMDB", function () { me.openSearch("https://www.google.co.uk/search?q=imdb+parents+guide+TESTSEARCH"); });
                //me.addLink(me.ulSearch, "YouTube", function () { me.openSearch("http://www.youtube.com/results?search_query=TESTSEARCH"); });
                //me.addLink(me.ulSearch, "Lovefilm", function () { me.openSearch("http://www.amazon.co.uk/s/ref=nb_sb_noss_2?url=search-alias%3Ddvd-bypost&field-keywords=TESTSEARCH"); });
                //me.addLink(me.ulSearch, "Locate TV", function () { me.openSearch("http://www.locatetv.com/search?q=TESTSEARCH"); });
                me.addLink(me.ulSearch, "Amazon", function () { me.openSearch("http://www.amazon.co.uk/s/ref=nb_sb_noss_1?url=search-alias%3Daps&field-keywords=TESTSEARCH&x=0&y=0"); });

                $('body').append(me.menu);

                me.refreshMenu();
            };

            me.addLink = function (parent, text, fn, href) {
                var li = null;

                if (me.useOwnMenu) {
                    li = $("<li>")
						    .append($("<a>" + text + "</a>")
							    .click(fn)
							    .prop("href", href));
                }
                else {
                    li = $("<menuitem label='" + text + "'>")
					        .click(fn);
                }

                parent.append(li);
                return li;
            };

            me.addListItem = function (parent, text) {
                var li = null;

                if (me.useOwnMenu) {
                    li = $("<li>").append($("<span>" + text + "</span>"));
                }
                else {
                    li = $("<menuitem label='" + text + "'>");
                }

                parent.append(li);
                return li;
            };

            me.addSeparator = function (parent) {
                if (me.useOwnMenu) {
                    return me.addListItem(parent, "").addClass("separator");
                }
                else {
                    var hr = $("<menu>");
                    parent.append(hr);
                    return hr;
                }
            };

            me.refreshMenu = function () {
                if (me.menu) {
                    if (me.doAuto) {
                        me.linkDisableAutoReadr.show();
                        me.linkEnableAutoReadr.hide();
                    }
                    else {
                        me.linkDisableAutoReadr.hide();
                        me.linkEnableAutoReadr.show();
                    }

                    if (me.foundUserStyle) {
                        me.userStyleSeparator.show();
                        me.linkReloadStyle.show();

                        if (!me.reloadStyleOnDblClickIsBound) {
                            me.linkReloadStyleOnDblClick.show();
                        }
                    }
                    else {
                        me.userStyleSeparator.hide();
                        me.linkReloadStyle.hide();
                        me.linkReloadStyleOnDblClick.hide();
                    }

                    if (me.activeUserStyle) {
                        me.linkUnloadStyle.show();
                    }
                    else {
                        me.linkUnloadStyle.hide();
                    }

                    if (me.activeReadr) {
                        me.separatorRead.show();
                        me.linkUndoReadr.show();
                        me.linkLinkFontUp.show();
                        me.linkLinkFontDown.show();
                        me.linkRunReadrPlus.show();
                    }
                    else {
                        me.separatorRead.hide();
                        me.linkUndoReadr.hide();
                        me.linkLinkFontUp.hide();
                        me.linkLinkFontDown.hide();
                        me.linkRunReadrPlus.hide();
                    }
                }
            };

            me.addStyle = function (css) {
                try {
                    GM_addStyle(css);
                }
                catch (ex) {
                    var s = document.createElement('style');
                    s.setAttribute('id', "user-web-menu-css");
                    s.setAttribute('rel', 'stylesheet');
                    s.setAttribute('type', 'text/css');
                    s.innerText = css;
                    document.head.appendChild(s);
                }
            };

            me.addStyles = function () {
                me.addStyle(
                    '.user-web-menu { ' +
                        'text-align: left !important;' +
                        'padding: 0 !important;' +
                        'position: absolute;' +
                        'border: solid 1px #000;' +
                        'font-family: calibri;' +
                        'font-size: 12px;' +
                        'color: #000;' +
                        'z-index: 999999999;' +
                        'text-align: center;' +
                    '}' +
                    '.user-web-menu, .user-web-menu *, .user-web-menu ul li a { ' +
                        'font-family: Corbel, URW Gothic L, Ubuntu Light, DejaVu Sans, Courier New, Arial !important;' +
                        'font-size: 13px !important;' +
                        'line-height: 13px !important;' +
                        'color: #000 !important;' +
                        'background-color: #fff !important;' +
                        'text-align: left !important;' +
                        'margin: 0 !important;' +
                    '}' +
					'.user-web-menu ul {' +
                        'display: table-cell !important;' +
                    '}' +
                    '.user-web-menu ul.user-web-readr {' +
                        'border-right: solid 1px #000 !important;' +
                    '}' +
                    '.user-web-menu ul, .user-web-menu li {' +
                        'margin: 0 !important;' +
                        'padding: 0 !important;' +
                        'list-style-type: none !important;' +
                        'list-style: none !important;' +
                        'white-space: nowrap !important;' +
                    '}' +
                    '.user-web-menu a:visited {' +
                        ' color: #000 !important;' +
                    '}' +
                    '.user-web-menu a {' +
                        'text-decoration: none !important;' +
                        'cursor: pointer !important;' +
                    '}' +
                    '.user-web-menu li {' +
                        'border-top: solid 1px #ddd !important;' +
                    '}' +
                    '.user-web-menu li.bold * {' +
                        'font-weight: bold !important;' +
                    '}' +
                    '.user-web-menu li.separator {' +
                        'padding: 0 !important;' +
                        'border-top: solid 1px #aaa !important;' +
                    '}' +
                    '.user-web-menu li.separator span {' +
                        'padding: 0 !important;' +
                    '}' +
                    '.user-web-menu a, .user-web-menu span {' +
                        'padding: 1px 10px !important;' +
                        'font-weight: normal !important;' +
                        'display: block !important;' +
                    '}' +
                    '.user-web-menu span {' +
                        'color: #888 !important;' +
                        'font-style: italic !important;' +
                    '}' +
                    '.user-web-menu a:hover {' +
                        'background-color: #def !important;' +
                    '}' +
                    '.readr-container a {' +
                        'text-decoration: none !important;' +
                        'border-bottom: 1px dotted #ddd !important;' +
                    '}' +
                    '.readr-container h1, .readr-container h2, .readr-container h3, .readr-container h4 {' +
                        'font-family: Corbel, URW Gothic L, Ubuntu Light, DejaVu Sans, Courier New, Arial !important;' +
                        'font-weight: bold !important;' +
                    '}' +
                    '.readr-container img + * {' +
                        'font-style: italic !important;' +
                    '}' +
                    me.getReadrFont()
                );
            };

            me.getReadrFont = function () {
                return '.readr-container p, .readr-container ul, .readr-container li, .readr-container a, .readr-container img + * {' +
                            'font-family: Corbel, URW Gothic L, Ubuntu Light, DejaVu Sans, Courier New, Arial !important;' +
                            'text-align: justify !important;' +
                            'font-size: ' + me.fontSize + 'px !important;' +
                            'line-height: ' + me.getLineHeight() + 'px !important;' +
                        '}';
            };

            /* menu actions ********************************************************************************************************************** */

            me.tryAutoReadr = function () {
                if (me.doAuto) {
                    me.run(function () {
                        me.addStyles();
                        me.runReadr(null, "auto");
                    });
                }
                else {
                    me.log("readr auto", "disabled");
                }
            };

            me.runReadr = function (e, options) {
                if (window.getSelection) {
                    window.getSelection().removeAllRanges();
                }
                else if (document.selection) {
                    document.selection.empty();
                }

                var target = e ? e.target : $("body")[0];

                userWebStyle.load(target, options);
                me.refreshMenu();
            };

            me.undoReadr = function () {
                userWebStyle.unload();
                me.refreshMenu();
            };

            me.disableAutoReadr = function () {
                me.undoReadr();
                me.cookie("auto", false);
                me.doAuto = false;
                me.refreshMenu();
            };

            me.enableAutoReadr = function () {
                me.cookie("auto", true);
                me.doAuto = true;
                me.refreshMenu();
                me.tryAutoReadr();
            };

            me.setFont = function (change) {
                me.fontSize += change;
                me.log("setFont", me.fontSize, "/", me.getLineHeight());

                me.addStyle(me.getReadrFont());
            };

            me.getLineHeight = function () {
                return parseInt(me.fontSize * 1.6, 10);
            };

            me.setClipboard = function (url) {
                me.run(function () {
                    GM_setClipboard(me.selectedText.trim());
                });
            };

            me.openSearch = function (url) {
                me.run(function () {
                    window.open(url.replace("TESTSEARCH", encodeURIComponent(me.selectedText.trim()).replace(/%20/g, "+")), "", "");
                });
            };

            me.navigateTo = function (url) {
                me.run(function () {
                    url = url.trim();

                    if (url.indexOf("http") != 0) {
                        url = "http://" + url;
                    }

                    window.open(url, "", "");

                });
            };

            /* user style ********************************************************************************************************************** */

            me.loadUserStyle = function () {

                var config = {
                    //bbc_news: { exp: /bbc\.co\.uk\/(news|sport|nature)/i },
                    bbc_weather: { exp: /bbc\.co\.uk\/(weather)/i },
                    boing_boing: { exp: /boingxboing\.net/i },
                    feedly: { exp: /\/\/feedly\.com/i },
                    //gmail: { exp: /mail\.google\.com/i },                  
                    google_calendar: { exp: /google\.com\/calendar/i },
                    google_keep: { exp: /keep\.google\.com/i },
                    google_maps: { exp: /maps\.google\.co/i },
                    google_search: { exp: /google\.(co\.uk|com)\/(search|webhp)/i },
                    guardian: { exp: /(guardian\.co\.uk)|theguardian\.com/i },
                    //independent: { exp: /independent\.co\.uk/i },
                    //old_reader: { exp: /theoldreader\.com/i },
                    outlook: { exp: /portal\..*com\/owa/i },
                    pocket: { exp: /getpocket\.com/i },
                    private_eye: { exp: /private-eye\.co\.uk/i },
                    stack_overflow: { exp: /stackoverflow\.com/i },
                    test: { exp: /(testlocal|testlive|testinject|testxx)\.htm/i },
                    tutorials_point: { exp: /tutorialspoint\.com/i },
                    yammer: { exp: /yammer\.com/i },
                    wikipedia: { exp: /wikipedia\.org/i }
                    //you_tube: { exp: /youtube\.com/i },
                };

                me.foundUserStyle = false;

                for (var name in config) {
                    var cfg = config[name];
                    cfg.name = name;

                    if (me.url.match(cfg.exp) != null) {
                        me.currentConfig = cfg;

                        if (cfg.exp != "") {
                            me.foundUserStyle = true;
                            me.loadUserStyleSheet(name.replace(/_/ig, "-"));
                            break;
                        }
                    }
                }

                if (!me.foundUserStyle) {
                    me.log("no userstyle match", me.url);
                }

                me.activeUserStyle = me.foundUserStyle;
                me.refreshMenu();
            };

            me.getUrl = function (path) {
                var unique = me.debug.uniqueUrls ? "?" + new Date().valueOf() : "";
                return me.getRoot() + path + unique;
            };

            me.loadUserStyleSheet = function (name) {
                var url = me.getUrl("Styles/" + name + ".css");

                me.log("inserting style", url);

                if (me.userStyleSheet == null) {
                    var s = document.createElement('link');
                    s.setAttribute('id', "user-web-css");
                    s.setAttribute('rel', 'stylesheet');
                    s.setAttribute('type', 'text/css');
                    document.head.appendChild(s);
                    me.userStyleSheet = s;
                }

                me.userStyleSheet.setAttribute('href', url);
                me.activeUserStyle = true;
            };

            me.unloadUserStyle = function () {
                me.userStyleSheet.setAttribute('href', "");
                me.activeUserStyle = false;
                me.refreshMenu();
            };
        };

        /* --------------------------------------------------------------- */

        var userWebStyle = new function () {
            var me = this;
            me.url = document.location.href;
            me.loadAttempts = 0;
            me.el0 = null;
            me.el = null;
            me.els = [];

            me.load = function (target, options) {
                me.options = options || "";

                //if (me.options) {
                //    me.log("readr options", me.options);
                //}

                if (target == null) {
                    me.log("readr binding", "mouseUpStart");
                    $('body').bind("mouseup.uws", me.mouseUpStart);
                }
                else {
                    //me.log("readr target", me.elToString($(target)));
                    me.findFromTarget(target);
                }
            };

            me.unload = function () {
                $(".readr-container").removeClass("readr-container");
                userWeb.activeReadr = false;
            };

            me.mouseUpStart = function (e) {
                userWeb.run(function () {
                    $('body').unbind("mouseup.uws");

                    me.findFromTarget(e.target);
                });
            };

            me.findFromTarget = function (target) {
                me.el0 = $(target);
                me.el = me.el0;
                me.els.push(me.el);

                var main = null;

                if (me.options.indexOf("popout") == -1) {
                    main = me.findMain(me.el);
                }
                else {
                    me.log("readr popout", "skipping auto find");
                }

                if (me.options.indexOf("remove-") > -1) {
                    if (main) {
                        me.log("removing");
                        main.remove();
                    }
                    else {
                        me.log("column not found");
                        alert("column not found");
                    }

                    return;
                }

                if (main) {
                    me.PsOnly = true;
                    me.el = main;
                    me.found();
                    me.lastTarget = target;
                }
                else if (me.options.indexOf("auto") != -1) {
                    me.log("readr not found main", "ending");
                }
                else {
                    me.boundAdvanced = true;
                    me.PsOnly = false;
                    me.el0.css("background-color", "orange");
                    me.log("readr not found main", "adding bindings");

                    $('body').bind("keyup.uws", me.keyUp);
                    $('body').bind("mouseup.uws", me.mouseUpNext);

                    document.oncontextmenu = function () {
                        return false;
                    };
                }
            };

            me.findMain = function (el) {
                var ps = el.find("p");

                if (ps.length > 3) {
                    me.log("main found", me.elToString(el));
                    return el;
                }

                var parent = el.parent();

                if (parent.length == 0) {
                    me.log("main not found");
                    return null;
                }

                //me.log("findMain", parent.width(), el.width());

                if (me.options.indexOf("remove-cell") > -1) {
                    if (parent.height() > el.height() + 30) {
                        me.log("main found", me.elToString(el));
                        return el;
                    }
                }

                if (parent.width() > el.width() + 30) {
                    me.log("main found", me.elToString(el));
                    return el;
                }

                return me.findMain(parent);
            };

            me.elToString = function (el) {
                try {
                    var res = "<" + el.prop("tagName");
                    var id = el.attr("id");

                    if (id) {
                        res += " id='" + id + "'";
                    }

                    var class1 = el.prop("class");
                    if (class1) {
                        res += " class='" + class1 + "'";
                    }

                    return res + ">"; ;
                }
                catch (ex) {
                    return "failed to log el: " + ex.message;
                }
            };

            me.keyUp = function (e) {
                userWeb.run(function () {
                    switch (e.keyCode) {
                        case 27: //esc
                            me.cancelFind();
                            break;
                        case 13: //enter
                            me.found();
                            break;
                        case 37: //back
                            if (me.el != me.el0) {
                                me.el.css("background-color", "");
                                me.els.pop();
                                me.el = me.els[me.els.length - 1];
                            }
                            break;
                        case 39: //forward
                            me.findNext();
                            break;
                    }
                });
            };

            me.mouseUpNext = function (e) {
                userWeb.run(function () {
                    switch (e.button) {
                        case 0:
                            me.findNext(); //chrome
                            break;
                        case 1:
                            if (document.all) { //IE
                                me.findNext();
                            }
                            break;
                        case 2: //right click
                            window.setTimeout(function () {
                                me.found();
                            }, 1);
                            break;
                    }
                });
            };

            me.findNext = function () {
                if (me.el[0].tagName == "BODY") {
                    return;
                }

                me.el = me.el.parent();

                if (me.el[0].tagName == "BODY") {
                    me.el.css("background-color", "red");
                }
                else {
                    me.el.css("background-color", "gold");
                }

                me.el.addClass("uws-el");
                me.els.push(me.el);
            };

            me.exclude = /share|sharing|social|twitter|tool|related|comment|discussion|extra|contentWellBottom|kudo|$ad|keywords|secondary-column|furniture|hidden|embedded-hyper/;

            me.found = function () {
                var popout = me.options.indexOf("popout") > -1;
                var title = document.title;
                var root = userWeb.getRoot();

                me.cancelFind();
                me.originalHtml = $("html").html();

                if (popout) {
                    var rem = me.el.find("iframe, script, link, button, input, form, textarea").remove();

                    /*rem.each(function () {
                    me.log($(this).html());
                    });*/

                    var hid = me.el.find("*").filter(function (a, b, c) {
                        return this.className.match(me.exclude) !== null ||
                            typeof (this.id) != "string" ||
                            this.id.match(me.exclude) ||
                            $(this).css('visibility') == 'hidden';
                    });

                    /*hid.each(function () {
                    me.log($(this).html());
                    });*/

                    hid.remove();

                    me.el.find('*').attr('style', '');
                    me.findMainContainers(me.el);

                    var containerClass = me.el.hasClass("readr-container") ? " readr-container" : "";
                    var html = me.el.html();
                    var doc = [];

                    $("head").remove();
                    $("body").remove();

                    doc.push("<head>");
                    doc.push("<title>" + title + "</title>");
                    doc.push("<link rel='stylesheet' type='text/css' href='" + userWeb.getUrl("Styles/readr.css") + "'>");
                    doc.push("</head>");
                    doc.push("<body>");
                    doc.push("<div class='readr-inner" + containerClass + "'>");
                    doc.push("<h1>" + title + "</h1>");
                    doc.push(html);

                    doc.push("<div class='readr-links'>");

                    var u = document.location.href.split("#")[0].split("/");

                    if (u[u.length - 1] == "") {
                        u.pop();
                    }

                    while (u.length > 2) {
                        doc.push("<a href=" + u.join("/") + ">" + u.join("/") + "</a><br />");
                        u.pop();
                    }

                    doc.push("</div>");
                    doc.push("</div>");
                    doc.push("</body>");

                    $("html").html(doc.join(""));

                    me.el = null;
                    me.el0 = null;
                    me.els = [];
                }
                else {
                    if (me.PsOnly) {
                        me.findMainContainers(me.el);
                    }
                    else {
                        me.el.addClass("readr-container"); ;
                    }
                }

                userWeb.activeReadr = true;
                userWeb.refreshMenu();
            };

            me.cancelFind = function () {
                if (me.boundAdvanced) {
                    $(".uws-el").css("background-color", "");
                    me.el0.css("background-color", "");
                    me.boundAdvanced = false;
                    $("*").unbind(".uws");
                    document.oncontextmenu = null;
                }
            };

            me.findMainContainers = function (content) {
                var paras = $(content).find("p");
                var parents = [];

                paras.parent().data("readrParentId", null)

                var parentId = 0;

                for (var i = 0; i < paras.length; i++) {
                    var $para = $(paras[i]);
                    var $parent = $para.parent();

                    if ($parent.data("readrParentId") == null) {
                        $parent.data("readrParentId", parentId);
                        parents[$parent.data("readrParentId")] = {
                            el: $parent,
                            count: 1,
                            parentId: parentId
                        };
                        parentId++;
                    }
                    else {
                        var id = $parent.data("readrParentId");

                        parents[id].count++;
                    }
                }

                if (parentId > 0) {
                    for (var j = 0; j < parents.length; j++) {
                        if (parents[j].count > 0) {
                            parents[j].el.addClass("readr-container");
                        }
                    }
                }
            };

            me.log = function (text1, text2) {
                log.apply(this, arguments);
            };
        };

        /* --------------------------------------------------------------- */

        window.setTimeout(function () {
            try {
                userWeb.load();
            }
            catch (ex) {
                log("error", ex.message);
            }
        }, 100);
    }
    else {
        log("skipping frame", document.location.href);
    }
}
catch (ex) {
    if (ex.message.indexOf("accessing a cross-origin frame") > -1) {
        log("frame", ex.message);
    }
    else {
        log("error", ex.message);
    }
}

function log() {

    var text1 = "", text2 = "";

    if (arguments.length > 0) {
        text1 = arguments[0];
    }

    if (arguments.length > 1) {
        for (var i = 1; i < arguments.length; i++) {
            text2 += arguments[i] + " ";
        }
    }

    text1 = text1.trim();
    text2 = text2.trim();

    if (text2 != null) {
        if (text1.length < 20) {
            text1 = text1 + Array(21 - text1.length).join(" ");
        }

        if (text1.length > 20) {
            text1 = text1.substr(0, 20);
        }

        text1 = text1 + ": " + text2;
    }

    if (text1.length > 100) {
        text1 = text1.substr(0, 100) + "...";
    }

    try {
        console.log("[user-web] " + text1);
    }
    catch (ex) {
        alert("[user-web] " + text1 + "\r\r" + ex.message);
    }
};
